package com.atlin.demo_client.manage;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.atlin.demo_client.config.ConfigInfo;
import com.atlin.demo_client.config.ConfigInfoHelper;
import com.atlin.demo_client.model.CdsSyncCheckVo;
import com.atlin.demo_client.model.ClientCode;
import com.atlin.demo_client.model.ClientFile;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author atlin
 * @description 同步入口
 * @createDate 2025/9/3 17:10
 */
@Slf4j
@Component
@AllArgsConstructor
public class SyncManage implements CommandLineRunner {

    private static final String GATEWAY = "http://127.0.0.1:8089/api";

    private static final int TIMOUT = 50000;


    /**
     * 同步客户端code
     */
    public void syncClientCode() {
        ConfigInfo configInfo = ConfigInfoHelper.getConfigInfo();

        HashMap<String, Object> param = new HashMap<>();
        param.put("userId", configInfo.getUserId());
        param.put("code", configInfo.getClientCode());
        param.put("folderPath", configInfo.getStorageDir());
        String body = HttpRequest.post(GATEWAY + "/clientCode/add")
                .body(JSONUtil.toJsonStr(param))
                .timeout(TIMOUT)
                .execute().body();
        JSONObject res = JSONUtil.parseObj(body);
        log.info("同步客户端code: {}", res);
    }

    /**
     * 文件同步校验
     *
     * @param clientCode 客户端code
     */
    public List<CdsSyncCheckVo> syncCheck(String clientCode) {
        HashMap<String, Object> param = new HashMap<>();
        param.put("clientCode", clientCode);
        String body = HttpRequest.get(GATEWAY + "/clientCode/syncCheck")
                .form(param)
                .timeout(TIMOUT)
                .execute().body();
        return JSONUtil.toList(body, CdsSyncCheckVo.class);
    }

    /**
     * 上传同步
     *
     * @param file       文件
     * @param clientCode code
     * @return
     */
    public static void uploadFile(File file, ClientCode clientCode) {
        // 创建请求
        HttpRequest request = HttpRequest.post(GATEWAY + "/clientFile/upload")
                .timeout(TIMOUT)
                .form("file", file)
                .form("code", clientCode.getCode())
                .form("folderPath", clientCode.getFolderPath())
                .form("clientCode", clientCode);

        // 发送请求并获取响应
        HttpResponse response = request.execute();

        // 处理响应
        if (response.isOk()) {
            log.info("[{}] ------> ok", request.getUrl());
        } else {
            log.error("[{}] ------> fail", request.getUrl());
            throw new RuntimeException("文件上传失败，状态码：" + response.getStatus());
        }
    }

    public void downloadFile(CdsSyncCheckVo cdsSyncCheckVo, String clientCode) {
        ConfigInfo configInfo = ConfigInfoHelper.getConfigInfo();

        ClientFile clientFile = new ClientFile();
        clientFile.setFileMetadataId(cdsSyncCheckVo.getFileMetadataId());
        clientFile.setClientCodeId(cdsSyncCheckVo.getClientCodeId());
        clientFile.setClientCode(configInfo.getClientCode());

        HttpRequest request = HttpRequest.post(GATEWAY + "/clientFile/download")
                .timeout(TIMOUT)
                .body(JSONUtil.toJsonStr(clientFile));

        // 发送请求并获取响应
        HttpResponse response = request.execute();

        // 处理响应
        if (response.isOk()) {
            log.info("[{}] ------> ok", request.getUrl());

            saveFile(response, cdsSyncCheckVo);
        } else {
            log.error("[{}] ------> fail", request.getUrl());
            throw new RuntimeException("文件下载失败，状态码：" + response.getStatus());
        }
    }

    /**
     * 文件同步
     */
    public void sync() {
        ConfigInfo configInfo = ConfigInfoHelper.getConfigInfo();
        String code = configInfo.getClientCode();

        List<CdsSyncCheckVo> cdsSyncCheckVoList = syncCheck(code);

//        Map<String, CdsSyncCheckVo> cdsSyncCheckHashMap = cdsSyncCheckVoList.stream().collect(Collectors.toMap(CdsSyncCheckVo::getFileHash,
//                v -> v,
//                (a, b) -> a));
//        Set<String> cdsSyncCheckHashSet = cdsSyncCheckHashMap.keySet();

        Map<String, List<CdsSyncCheckVo>> cdsSyncCheckHashMap = cdsSyncCheckVoList.stream().collect(Collectors.groupingBy(CdsSyncCheckVo::getFileHash));
        Set<String> cdsSyncCheckHashSet = cdsSyncCheckHashMap.keySet();

        // 上传文件
        ArrayList<File> needUploadFile = getNeedUploadFile(cdsSyncCheckHashSet);
        for (File file : needUploadFile) {
//            File file = new File("D:\\Temp\\openapi.json");
            ClientCode clientCode = new ClientCode();
            clientCode.setCode(configInfo.getClientCode());
            clientCode.setFolderPath(getFileSuffix(file.getPath()));
            uploadFile(file, clientCode);
        }

        ArrayList<String> needDownloadFile = getNeedDownloadFile(cdsSyncCheckHashSet);
        for (String fileHash : needDownloadFile) {
            List<CdsSyncCheckVo> cdsSyncCheckVos = cdsSyncCheckHashMap.get(fileHash);
            cdsSyncCheckVos.forEach(v -> downloadFile(v, configInfo.getClientCode()));
        }


    }


    @Override
    public void run(String... args) throws Exception {
        log.info("-----> 文件同步助手初始化");
        ConfigInfoHelper.init();
        syncClientCode();
        log.info("-----> 文件同步助手初始化成功");
        log.info("-----> 开始同步文件");
        sync();
        log.info("-----> 文件同步完成");
    }


    public ArrayList<File> getNeedUploadFile(Set<String> cdsSyncCheckHashSet) {
        ConfigInfo configInfo = ConfigInfoHelper.getConfigInfo();
        List<ConfigInfo.DirectoryInfo> directoryInfoList = configInfo.getDirectoryInfoList();
        // 上传同步文件夹校验
        ArrayList<File> needUpload = new ArrayList<>();
        for (ConfigInfo.DirectoryInfo directoryInfo : directoryInfoList) {
            List<File> fileList = FileUtil.loopFiles(new File(directoryInfo.getSyncDirectory()));
            for (File file : fileList) {
                String md5Hex = DigestUtil.md5Hex(file);

                if (!cdsSyncCheckHashSet.contains(md5Hex)) {
                    needUpload.add(file);
                }
            }
        }
        return needUpload;
    }

    public ArrayList<String> getNeedDownloadFile(Set<String> cdsSyncCheckHashSet) {
        ConfigInfo configInfo = ConfigInfoHelper.getConfigInfo();
        String storageDir = configInfo.getStorageDir();
        // 下载同步文件夹校验
        ArrayList<String> needDownload = new ArrayList<>(cdsSyncCheckHashSet);
        List<File> fileList = FileUtil.loopFiles(new File(storageDir));
        for (File file : fileList) {
            String md5Hex = DigestUtil.md5Hex(file);
            needDownload.remove(md5Hex);
        }
        return needDownload;
    }

    public void saveFile(HttpResponse response, CdsSyncCheckVo cdsSyncCheckVo) {
        ConfigInfo configInfo = ConfigInfoHelper.getConfigInfo();
        String storageDir = configInfo.getStorageDir();
        // 保存文件的目录
        File dir = FileUtil.mkdir(storageDir + cdsSyncCheckVo.getFilePath());
        // 目标文件（可以用后端返回的文件名，也可以自己拼接）
        //  cdsSyncCheckVo.getFileName()
        File targetFile = FileUtil.file(dir);

        // 将响应体写入文件
        response.writeBody(targetFile);

        log.info("文件已下载保存到: {}", targetFile.getAbsolutePath());
    }

    public String getFileSuffix(String filePath) {
        Set<String> directoryPrefixSet = ConfigInfoHelper.getDirectoryPrefixSet();

        for (String prefix : directoryPrefixSet) {
            if (StrUtil.contains(filePath, prefix)) {
                return StrUtil.subBefore(StrUtil.subAfter(filePath, prefix, false), File.separator, true);
            }
        }
        return StrUtil.subBefore(StrUtil.subAfter(filePath, ":", true), File.separator, true);
    }
}
